import logging
import sys
from typing import Dict, List, Any, Union
from pyhandylang.vars_stack import CallStack

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S', filemode='w')

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
TYPE_VARSPACE = Dict[str, Any]
###   定义分隔符   ###
LEVEL_TOKEN = '| '
###   是否打印详细信息   ###
AstDebug = False
###   全局变量保存字典   ###
functions: Dict[str, "FunctionDefine"] = {}  # 等待实现，现在还没有实现函数定义的功能！
callStack = CallStack()


###   定义数字   ###
class Number():
    def __init__(self, value):
        self.type = 'number'
        self.value = value

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret = ret + str(self.value)
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 返回变量数值
        return self.value


###   定义常量   ###
class Const():
    def __init__(self, value):
        self.type = 'const'
        self.value = value

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret = ret + str(self.value)
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 返回变量数值
        return self.value


###   定义字符串   ###
class Str():
    def __init__(self, value):
        self.type = 'str'
        self.value = value

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret = ret + str(self.value)
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 返回变量数值
        return self.value


###   定义双目运算符，+   ###
class BinOpPlus():
    def __init__(self, left, right):
        self.type = 'binop_+'
        # 运算符
        self.op = '+'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug:
            print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" + self.left.getTree(level + 1) + "\n" + \
               self.right.getTree(level + 1)

    def exe(self):
        if AstDebug:
            print('type = ', self.type, ', fun = exe')
        # 执行四则运算
        return self.left.exe() + self.right.exe()


###   定义双目运算符，-   ###
class BinOpMinus():
    def __init__(self, left, right):
        self.type = 'binop_-'
        # 运算符
        self.op = '-'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行四则运算
        return self.left.exe() - self.right.exe()


###   定义双目运算符，*   ###
class BinOpTimes():
    def __init__(self, left, right):
        self.type = 'binop_*'
        # 运算符
        self.op = '*'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行四则运算
        return self.left.exe() * self.right.exe()


###   定义双目运算符，/   ###
class BinOpDivde():
    def __init__(self, left, right):
        self.type = 'binop_/'
        # 运算符
        self.op = '/'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行四则运算
        return self.left.exe() / self.right.exe()


###   定义双目运算符，%   ###
class BinOpMod():
    def __init__(self, left, right):
        self.type = 'binop_%'
        # 运算符
        self.op = '%'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行四则运算
        return self.left.exe() % self.right.exe()


###   定义比较运算符，>   ###
class CompareOpGt():
    def __init__(self, left, right):
        self.type = 'compareop_>'
        # 运算符
        self.op = '>'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        return self.left.exe() > self.right.exe()


###   定义比较运算符，>=   ###
class CompareOpGte():
    def __init__(self, left, right):
        self.type = 'compareop_>='
        # 运算符
        self.op = '>='
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        return self.left.exe() >= self.right.exe()


###   定义比较运算符，<   ###
class CompareOpLt():
    def __init__(self, left, right):
        self.type = 'compareop_<'
        # 运算符
        self.op = '<'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        return self.left.exe() < self.right.exe()


###   定义比较运算符，<=   ###
class CompareOpLte():
    def __init__(self, left, right):
        self.type = 'compareop_<='
        # 运算符
        self.op = '<='
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        return self.left.exe() <= self.right.exe()


###   定义测试运算符，==   ###
class CompareOpEq():
    def __init__(self, left, right):
        self.type = 'compareop_=='
        # 运算符
        self.op = '=='
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        return self.left.exe() == self.right.exe()


###   定义测试运算符，!=   ###
class CompareOpNeq():
    def __init__(self, left, right):
        self.type = 'compareop_!='
        # 运算符
        self.op = '!='
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        return self.left.exe() != self.right.exe()


###   定义测试运算符，and   ###
class BoolOpAnd():
    def __init__(self, left, right):
        self.type = 'boolop_and'
        # 运算符
        self.op = 'and'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行逻辑操作
        return self.left.exe() and self.right.exe()


###   定义测试运算符，or   ###
class BoolOpOr():
    def __init__(self, left, right):
        self.type = 'boolop_or'
        # 运算符
        self.op = 'or'
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行逻辑操作
        return self.left.exe() or self.right.exe()


###   定义赋值运算符   ###
class Assign():
    def __init__(self, id, expression):
        self.type = 'assign'
        # 被赋值变量
        self.id = id
        # 表达式
        self.expression = expression

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + "=\n" \
               + LEVEL_TOKEN * (level + 1) + str(self.id) \
               + "\n" + self.expression.getTree(level + 1)

    def exe(self):
        # 执行赋值操作
        if AstDebug:
            print('type = ', self.type, ', fun = exe')
        ret = self.expression.exe()
        callStack.setVar(self.id, ret)


###   定义变量   ###
class Name():
    def __init__(self, id):
        self.type = 'name'
        self.id = id

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret = ret + str(self.id)
        return ret

    def exe(self):
        if AstDebug == True:
            print('type = ', self.type, ', fun = exe')
        # 返回变量名字
        return callStack.getVar(self.id)


###   定义Print   ###
class Print():
    def __init__(self, value):
        self.type = 'print'
        self.value = value

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + 'PRINT \n' + self.value.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 打印变量
        print(self.value.exe())


###   定义程序段   ###
class StatementList():
    def __init__(self):
        self.type = 'statementlist'
        self.statement_list = []

    def add_statement(self, statement_list):
        self.statement_list.append(statement_list)

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = ""
        x = ""
        for item in self.statement_list:
            ret += x + item.getTree(level)
            x = "\n"
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 迭代，得到每一个值
        result = []
        for i, statement in enumerate(self.statement_list):
            try:
                logger.debug("executing:%s" % statement)
                result.append(statement.exe())

                if callStack.requestReturn:
                    logger.debug(
                        "离开当前栈帧%s,进度%d/%d语句，" % (str(callStack.currentFrame()), i + 1, len(self.statement_list)))
                    break
                logger.debug(statement)

            except TypeError as e:
                logger.fatal(statement)
                raise e
        return result


###   定义If   ###
class If():
    def __init__(self, test, body, orelse):
        self.type = 'if'
        # 测试条件
        self.test = test
        # if部分的代码
        self.body = body
        # else部分的代码
        self.orelse = orelse

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        if not self.orelse:
            ret += "IF\n" + self.test.getTree(level + 1) \
                   + "\n" + self.body.getTree(level + 1)
        else:
            ret += "IF\n" + self.test.getTree(level + 1) \
                   + "\n" + self.body.getTree(level + 1) \
                   + "\n" + self.orelse.getTree(level + 1)
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行IF操作
        if self.test.exe():
            self.body.exe()
        else:
            if self.orelse != None:
                self.orelse.exe()


class For():
    def __init__(self, test, body, orelse=None, tmpIdentifier=None, start=None, end=None, step=None):
        self.type = "for"
        self.test = test
        self.body = body
        self.orelse = orelse
        self.tmpIdentifier = tmpIdentifier
        self.start = start
        self.end = end

        self.step = step

    def getTree(self, level=0):
        if AstDebug:
            print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        if not self.orelse:
            ret += "FOR\n" + "%s" % 123  # self.test.getTree(level + 1) \
            # + "\n" + self.body.getTree(level + 1)
        else:
            ret += "FOR\n" + self.test.getTree(level + 1) \
                   + "\n" + self.body.getTree(level + 1) + "\n" \
                   + self.orelse.getTree(level + 1)
        return ret

    def exe(self):
        if AstDebug == True:
            print('type = ', self.type, ', fun = exe')
        if self.start is not None:
            if self.step is None:
                iterator = range(self.start, self.end)
            else:
                iterator = range(self.start, self.end, self.step)
            for _iter_val in iterator:
                callStack.setVar(self.tmpIdentifier, _iter_val)
                self.body.exe()
        else:
            while self.test.exe():
                self.body.exe()
            else:
                if self.orelse != None:
                    self.orelse.exe()


###   定义返回Return   ###
class Return():
    def __init__(self, body, vars: List[str] = None):
        self.type = 'while'
        # 测试条件
        # while部分的代码
        self.body = body
        self.vars: List = [] if vars is None else vars
        # else部分的代码
        # self.orelse = orelse

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret += "return %s" % self.vars  # + "\n"# + self.body.getTree(level + 1)
        return ret

    def exe(self):
        if AstDebug == True:
            print('type = ', self.type, ', fun = exe')
        vars = []
        for var in self.vars:
            vars.append(var.exe())
        callStack.requestReturn = True
        callStack.setReturnVars(vars)


###   定义While   ###
class While():
    def __init__(self, test, body, orelse):
        self.type = 'while'
        # 测试条件
        self.test = test
        # while部分的代码
        self.body = body
        # else部分的代码
        self.orelse = orelse

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        if not self.orelse:
            ret += "WHILE\n" + self.test.getTree(level + 1) \
                   + "\n" + self.body.getTree(level + 1)
        else:
            ret += "WHILE\n" + self.test.getTree(level + 1) \
                   + "\n" + self.body.getTree(level + 1) + "\n" \
                   + self.orelse.getTree(level + 1)
        return ret

    def exe(self):
        if AstDebug == True:
            print('type = ', self.type, ', fun = exe')
        # 执行WHILE操作
        while self.test.exe():
            self.body.exe()
        else:
            if self.orelse != None:
                self.orelse.exe()


###   定义函数FunctionDefine   ###
class FunctionDefine():
    def __init__(self, test, body, name, params_list=None):
        self.type = 'function_define'
        # 测试条件
        self.test = test
        # while部分的代码
        self.body = body
        # else部分的代码
        self.name = name

        self.params_list: "ParamList" = params_list

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret += "Function Define: name:%s" % self.name + '\n'  # + self.test.getTree(level + 1) \
        ret += self.body.getTree(level + 1)

        return ret

    def exe(self):
        if AstDebug == True:
            print('type = ', self.type, ', fun = exe')
        functions[self.name] = self

    def getParamNames(self) -> List[str]:
        return self.params_list.params


class ParamList():
    def __init__(self, paramName1: 'Union[ParamList,Any]', paramName2: 'Union[ParamList,Any]' = None):
        paramName1 = [paramName1] if not isinstance(paramName1, ParamList) else paramName1.params
        if paramName2 is not None:
            paramName2 = [paramName2] if not isinstance(paramName2, ParamList) else paramName2.params
        else:
            paramName2 = []
        self.params: List[Name] = paramName1 + paramName2

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = ""
        x = ""
        for item in self.params:
            ret += x + item.getTree(level)
            x = "\n"
        return ret

    def exe(self):
        pass


###   定义函数调用FunctionCall   ###
class FunctionCall():
    def __init__(self, name, arguments=None, body=None):
        self.type = 'function_call'
        # 测试条件
        self.arguments = arguments
        self.name = name
        self.body = body

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret += "FunctionCall\n" + \
               self.body.getTree(level + 1) if self.body is not None else ""
        return ret

    def exe(self):
        if AstDebug == True:
            print('type = ', self.type, ', fun = exe')
        tmp_vars = {}
        body_res = []
        if isinstance(self.body, ExprList):
            body_res = self.body.exe() if self.body is not None else []
        elif self.body is not None:
            body_res = [self.body.exe()]

        if len(body_res) != 0:
            try:
                tmp_vars = {functions[self.name].getParamNames()[i]: body_res[i] for i in range(len(body_res))}
            except KeyError or IndexError:
                logger.fatal("函数有：%s，调用的函数的名称为：%s" % (functions, self.name))
                logger.fatal("形参列表：%s,实参输入：%s" % (functions[self.name].getParamNames(), body_res))
                logger.fatal(functions["add"].args)
                import traceback
                traceback.print_exc()
                sys.exit(0)
        callStack.addFrame(self.name, tmp_vars)
        try:
            functions[self.name].body.exe()
        except Exception as e:
            import traceback
            traceback.print_exc()
            sys.exit(0)
        callStack.popFrame()
        rets = callStack.getReturnVars()
        if len(rets) > 0:
            return rets[0]
        else:
            return None


###   定义列表   ###
class List():
    def __init__(self, values):
        self.type = 'list'
        self.values = values

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret += "LIST\n" + self.values.getTree(level + 1)
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 返回列表
        return self.values.exe()


###   定义For   ###

########################


###   定义双目运算符，四则运算   ###
class BinOp():
    def __init__(self, left, op, right):
        self.type = 'binop'
        # 运算符
        self.op = op
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行四则运算
        if self.op == '+':
            return self.left.exe() + self.right.exe()
        elif self.op == '-':
            return self.left.exe() - self.right.exe()
        elif self.op == '*':
            return self.left.exe() * self.right.exe()
        elif self.op == '/':
            return self.left.exe() / self.right.exe()
        elif self.op == '%':
            return self.left.exe() % self.right.exe()


###   定义测试运算符，AND，OR，   ###
class BoolOp():
    def __init__(self, op, left, right):
        self.type = 'boolop'
        # 运算符
        self.op = op
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug:
            print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug:
            print('type = ', self.type, ', fun = exe')
        # 执行逻辑操作
        if self.op == 'and':
            return self.left.exe() and self.right.exe()
        elif self.op == 'or':
            return self.left.exe() or self.right.exe()


###   定义比较运算符   ###
class Compare():
    def __init__(self, left, op, right):
        self.type = 'compare'
        # 运算符
        self.op = op
        # 左部分
        self.left = left
        # 右部分
        self.right = right

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        return LEVEL_TOKEN * level + self.op + "\n" \
               + self.left.getTree(level + 1) + "\n" \
               + self.right.getTree(level + 1)

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 执行比较运算
        if self.op == '>':
            return self.left.exe() > self.right.exe()
        elif self.op == '<':
            return self.left.exe() < self.right.exe()
        elif self.op == '>=':
            return self.left.exe() >= self.right.exe()
        elif self.op == '<=':
            return self.left.exe() <= self.right.exe()
        elif self.op == '==':
            return self.left.exe() == self.right.exe()
        elif self.op == '!=':
            return self.left.exe() != self.right.exe()


###   定义元组   ###
class Tuple():
    def __init__(self, values):
        self.type = 'tuple'
        self.values = values

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = LEVEL_TOKEN * level
        ret += "TUPLE\n" + self.values.getTree(level + 1)
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 返回元组
        return self.values.exe()


###
class ExprList():
    def __init__(self, expr1: Union[Any, "ExprList"], expr2: Union[Any, "ExprList"]):
        self.type = 'exprlist'
        list1 = [expr1] if not isinstance(expr1, ExprList) else expr1.expression_list
        list2 = [expr2] if not isinstance(expr2, ExprList) else expr1.expression_list
        self.expression_list = list1 + list2

    def add_expr_list(self, expression_list):
        self.expression_list.append(expression_list)

    def getTree(self, level=0):
        if AstDebug == True: print('type = ', self.type, ', fun = getTree')
        ret = ""
        x = ""
        for item in self.expression_list:
            ret += x + item.getTree(level)
            x = "\n"
        return ret

    def exe(self):
        if AstDebug == True: print('type = ', self.type, ', fun = exe')
        # 迭代，得到每一个值
        result = []
        for expression in self.expression_list:
            result.append(expression.exe())
        return result
